﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Aspire.Repository.EfCore
{
    public class RepositoryEfCore<TId, TEntity> : Repository<TId, TEntity>, IRepositoryEfCore<TId, TEntity>
         where TEntity : BaseEfCoreEntity<TId>, new()
    {
        private readonly DbContext _dbContext;
        public RepositoryEfCore(DbContext dbContext)
        {
            _dbContext = dbContext;
        }

        private IEntityType _entityType = default;
        public IEntityType EntityType
            => _entityType == default ? _entityType = _dbContext.Model.FindEntityType(typeof(TEntity)) : _entityType;

        private string _tableName = default;
        public override string TableName
            => _tableName == default ? _tableName = EntityType.GetTableName() : _tableName;

        private string _primaryKeyName = default;
        public override string PrimaryKeyName
            => _primaryKeyName == default ? _primaryKeyName = EntityType.FindPrimaryKey().Properties.First().Name : _primaryKeyName;

        public override string IdentityName => throw new System.NotImplementedException();

        public DbSet<TEntity> Query => throw new System.NotImplementedException();

        public override async Task<int> AddRangeAsync(IEnumerable<TEntity> entities)
        {
            await _dbContext.AddRangeAsync(entities);
            return await _dbContext.SaveChangesAsync();
        }

        public override async Task<TId[]> AddRangeThenIdsAsync(IEnumerable<TEntity> entities)
        {
            List<TId> ls = new List<TId>();

            foreach (TEntity entity in entities)
            {
                Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> t = await _dbContext.AddAsync(entity);
                ls.Add(t.Entity.Id);
            }

            _ = await _dbContext.SaveChangesAsync();
            return ls.ToArray();
        }

        public override async Task<int> DeleteRangeAsync(IEnumerable<TId> ids)
        {
            _dbContext.RemoveRange(ids.Select(x => new TEntity { Id = x }));
            return await _dbContext.SaveChangesAsync();
        }

        public override async Task<TEntity[]> GetByIdsAsync(IEnumerable<TId> ids)
        {
            return await Query.Where(x => ids.Contains(x.Id)).ToArrayAsync();
        }

        public override async Task<int> UpdateRangeAsync(IEnumerable<TEntity> entities)
        {
            _dbContext.UpdateRange(entities);
            return await _dbContext.SaveChangesAsync();
        }

        public virtual async Task<bool> UpdateAsync(TId id, Action<TEntity> updater)
        {
            TEntity e = await Query.FirstAsync(x => x.Id.Equals(id));
            updater(e);
            return await _dbContext.SaveChangesAsync() == 1;
        }

        public override async Task<int> ExecuteSqlRawAsync(string sql, params object[] param)
        {
            return await _dbContext.Database.ExecuteSqlRawAsync(sql, param);
        }

        public override async Task<TEntity[]> QuerySqlRawAsync(string sql, params object[] param)
        {
            return await Query.FromSqlRaw(sql, param).ToArrayAsync();
        }

        public override async Task<TEntity> UpdateThenEntityAsync(TEntity entity)
        {
            Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<TEntity> r = _dbContext.Update(entity);
            if (await _dbContext.SaveChangesAsync() == 1)
            {
                return r.Entity;
            }

            throw new System.Exception("异常详情待完善(更新数据失败)");
        }
    }
}
